/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package com.xieq.dota.modular.group.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xieq.dota.modular.group.entity.Group;
import com.xieq.dota.modular.group.mapper.GroupMapper;
import com.xieq.dota.modular.group.param.GroupAddParam;
import com.xieq.dota.modular.group.param.GroupEditParam;
import com.xieq.dota.modular.group.param.GroupIdParam;
import com.xieq.dota.modular.group.param.GroupPageParam;
import com.xieq.dota.modular.group.service.GroupService;
import com.xieq.dota.modular.match.param.*;
import com.xieq.dota.modular.match.result.GroupDrawResult;
import com.xieq.dota.modular.matchplayer.entity.MatchPlayer;
import com.xieq.dota.modular.matchplayer.service.MatchPlayerService;
import com.xieq.dota.modular.player.entity.Player;
import com.xieq.dota.modular.player.service.PlayerService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * 分组表Service接口实现类
 *
 * @author xieq
 * @date  2025/11/10 09:51
 **/
@Service
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements GroupService {

    private static final int DRAW_COUNT = 3;

    @Resource
    private PlayerService playerService;

    @Resource
    private MatchPlayerService matchPlayerService;

    @Override
    public List<GroupDrawResult> drawPlayers(GroupDrawParam param) {

        List<MatchPlayer> matchPlayers = matchPlayerService.lambdaQuery()
                .eq(MatchPlayer::getMatchId, param.getMatchId())
                .eq(MatchPlayer::getCardGroup, param.getDeckId())
                .isNull(MatchPlayer::getGroupId)
                .list();

        if (CollUtil.isEmpty(matchPlayers)) {
            return Collections.emptyList();
        }

        List<String> playerAccounts = matchPlayers.stream()
                .map(MatchPlayer::getPlayId)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(playerAccounts)) {
            return Collections.emptyList();
        }

        List<Player> players = playerService.lambdaQuery()
                .in(Player::getAccount, playerAccounts)
                .list();

        List<Player> drawPlayers = randomDraw(players, DRAW_COUNT);

        return drawPlayers.stream().map(player -> {
            GroupDrawResult result = new GroupDrawResult();
            result.setId(player.getId());
            result.setNickname(player.getNickname());
            result.setAccount(player.getAccount());
            result.setPosition(StrUtil.emptyToDefault(player.getPositions(), ""));
            result.setLevel(player.getAbility());
            result.setDescription(player.getTags());
            return result;
        }).collect(Collectors.toList());
    }

    private List<Player> randomDraw(List<Player> players, int count) {
        if (CollUtil.isEmpty(players) || count <= 0) {
            return Collections.emptyList();
        }

        Map<String, Player> distinct = players.stream()
                .filter(Objects::nonNull)
                .filter(player -> StrUtil.isNotBlank(player.getId()))
                .collect(Collectors.toMap(Player::getId, player -> player, (first, second) -> first, LinkedHashMap::new));

        List<Player> candidateList = new ArrayList<>(distinct.values());
        Collections.shuffle(candidateList, ThreadLocalRandom.current());

        if (candidateList.size() <= count) {
            return candidateList;
        }
        return new ArrayList<>(candidateList.subList(0, count));
    }

    @Override
    public List<GroupCaptainResult> captainList(GroupCaptainParam param) {

        List<MatchPlayer> matchPlayers = matchPlayerService.lambdaQuery()
                .eq(MatchPlayer::getMatchId, param.getMatchId())
                .isNull(MatchPlayer::getGroupId)
                .list();

        if (CollUtil.isEmpty(matchPlayers)) {
            return Collections.emptyList();
        }

        List<String> playerAccounts = matchPlayers.stream()
                .map(MatchPlayer::getPlayId)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(playerAccounts)) {
            return Collections.emptyList();
        }

        List<Player> players = playerService.lambdaQuery()
                .in(Player::getAccount, playerAccounts)
                .list();

        return players.stream().map(player -> {
            GroupCaptainResult result = new GroupCaptainResult();
            result.setCaptainId(player.getAccount());
            result.setCaptainName(player.getNickname());
            return result;
        }).collect(Collectors.toList());
    }

    @Override
    public Boolean update(GroupAddPlayerParam param) {

        if (param.getCaptain()) {
            // 其他玩家设置为非队长
            matchPlayerService.lambdaUpdate()
                    .set(MatchPlayer::getGroupId, null)
                    .set(MatchPlayer::getCaptain, false)
                    .eq(MatchPlayer::getGroupId, param.getGroupId())
                    .eq(MatchPlayer::getCaptain, true)
                    .update();
        }

        return matchPlayerService.lambdaUpdate()
                .set(MatchPlayer::getCaptain, param.getCaptain())
                .set(MatchPlayer::getGroupId, param.getGroupId())
                .eq(MatchPlayer::getPlayId, param.getPlayerId())
                .update();
    }

    @Override
    public List<GroupDrawResult> cardRemainPlayer(GroupDrawParam param) {

        List<MatchPlayer> matchPlayers = matchPlayerService.lambdaQuery()
                .eq(MatchPlayer::getMatchId, param.getMatchId())
                .eq(MatchPlayer::getCardGroup, param.getDeckId())
                .isNull(MatchPlayer::getGroupId)
                .list();
        if (CollUtil.isEmpty(matchPlayers)) {
            return Collections.emptyList();
        }
        List<String> playerAccounts = matchPlayers.stream()
                .map(MatchPlayer::getPlayId)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());

        List<Player> players = playerService.lambdaQuery()
                .in(Player::getAccount, playerAccounts)
                .list();

        return players.stream().map(player -> {
            GroupDrawResult result = new GroupDrawResult();
            result.setId(player.getId());
            result.setNickname(player.getNickname());
            result.setAccount(player.getAccount());
            result.setPosition(StrUtil.emptyToDefault(player.getPositions(), ""));
            result.setLevel(player.getAbility());
            result.setDescription(player.getTags());
            return result;
        }).collect(Collectors.toList());

    }

    @Override
    public Page<Group> page(GroupPageParam groupPageParam) {
        QueryWrapper<Group> queryWrapper = new QueryWrapper<Group>().checkSqlInjection();
        if(ObjectUtil.isAllNotEmpty(groupPageParam.getSortField(), groupPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(groupPageParam.getSortOrder());
            queryWrapper.orderBy(true, groupPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(groupPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(Group::getId);
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(GroupAddParam groupAddParam) {
        Group group = BeanUtil.toBean(groupAddParam, Group.class);
        this.save(group);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(GroupEditParam groupEditParam) {
        Group group = this.getById(groupEditParam.getId());
        BeanUtil.copyProperties(groupEditParam, group);
        this.updateById(group);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<GroupIdParam> groupIdParamList) {
        // 执行删除
        this.removeByIds(CollStreamUtil.toList(groupIdParamList, GroupIdParam::getId));

        matchPlayerService.lambdaUpdate()
                .set(MatchPlayer::getGroupId, null)
                .set(MatchPlayer::getCaptain, false)
                .in(MatchPlayer::getGroupId, CollStreamUtil.toList(groupIdParamList, GroupIdParam::getId))
                .update();
    }

    @Override
    public List<MatchGroupDetail> detail(String matchId) {
        List<Group> list = this.lambdaQuery().eq(Group::getMatchId, matchId).list();

        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }

        List<MatchPlayer> players = matchPlayerService.lambdaQuery().in(
                MatchPlayer::getGroupId,
                CollStreamUtil.toList(list, Group::getId)
        ).list();

        return CollStreamUtil.toList(list, group -> {
            MatchGroupDetail matchGroupDetail = new MatchGroupDetail();
            matchGroupDetail.setId(group.getId());
            matchGroupDetail.setMatchId(group.getMatchId());
            matchGroupDetail.setPropsRepick(group.getPropsRepick());
            matchGroupDetail.setPropsSkip(group.getPropsSkip());
            matchGroupDetail.setPropsVeto(group.getPropsVeto());
            // 队长
            players.stream().filter(MatchPlayer::getCaptain)
                    .filter(player -> group.getId().equals(player.getGroupId()))
                    .map(MatchPlayer::getPlayId)
                    .findFirst()
                    .ifPresent(matchGroupDetail::setCaptainId);

            // 队员
            List<String> memberIds = players.stream()
                    .filter(player -> group.getId().equals(player.getGroupId()))
                    .filter(player -> !player.getCaptain())
                    .map(MatchPlayer::getPlayId)
                    .collect(Collectors.toList());
            matchGroupDetail.setMemberIds(memberIds);
            return matchGroupDetail;
        });
    }


}
